﻿using OpenMms.Domain.Interface;
using OpenMms.Domain.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using OpenMms.Domain.ReponseModels;
using OpenMms.Domain.RequestModels;
using OpenMms.Common.Url;
using Z.EntityFramework.Plus;
using X.PagedList;

namespace OpenMms.Domain.BLL
{
    /// <summary>
    /// Wtite库
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public class BLLConstruct<TEntity>: IBLLConstruct<TEntity> where TEntity : class, new()
    {
        #region 注入
        /// <summary>
        /// 主库
        /// </summary>
        private OpenMmsDBContext _context;
        public BLLConstruct(OpenMmsDBContext context)
        {
            _context = context;
          
        }
        #endregion

        #region 事务控制

        /// <summary>
        /// 开启事务
        /// </summary>
        /// <returns></returns>
        public IDbContextTransaction BeginTrans()
        {
            return _context.Database.BeginTransaction();
        }

        /// <summary>
        /// 悲观事务锁定一行数据
        /// </summary>
        /// <param name="id"></param>
        public void LockRow(int id = 0)
        {
            _context.Database.ExecuteSqlCommand("set lock_timeout 100;select id from " + typeof(TEntity).Name + " with(updlock) where ID=@ID", new SqlParameter[] { new SqlParameter("@ID", id) });
        }
        #endregion

        #region 查询

        #region 按主键获取一个实体

        /// <summary>
        /// 按主键获取一个实体
        /// </summary>
        /// <param name="id">主键值</param>
        /// <returns>相应的实体</returns>
        public TEntity Find(int id)
        {
            return _context.Set<TEntity>().Find(id);
        }

        /// <summary>
        /// 按主键获取一个实体 异步
        /// </summary>
        /// <param name="id">主键值</param>
        /// <returns>相应的实体</returns>
        public async Task<TEntity> FindAsync(int id)
        {
            return await _context.Set<TEntity>().FindAsync(id);
        }

        #endregion

        #region 按条件获取一个实体

        /// <summary>
        /// 按条件获取一个实体
        /// </summary>
        /// <param name="where">lambda条件表达式</param>
        /// <returns>相应的实体</returns>
        public TEntity Find(Expression<Func<TEntity, bool>> where)
        {
            return _context.Set<TEntity>().Where(where).FirstOrDefault();
        }
        /// <summary>
        /// 按条件获取一个实体 异步
        /// </summary>
        /// <param name="where">lambda条件表达式</param>
        /// <returns>相应的实体</returns>
        public async Task<TEntity> FindAsync(Expression<Func<TEntity, bool>> where)
        {
            return await _context.Set<TEntity>().Where(where).FirstOrDefaultAsync();
        }
        #endregion

        #region 按条件获取一个实体列表

        /// <summary>
        /// 按条件获取一个实体列表
        /// </summary>
        /// <param name="where">lambda条件表达式</param>
        /// <returns>实体列表</returns>
        public List<TEntity> Query(Expression<Func<TEntity, bool>> where)
        {
            return _context.Set<TEntity>().Where(where).ToList();
        }

        /// <summary>
        /// 按条件获取一个实体列表 异步
        /// </summary>
        /// <param name="where">lambda条件表达式</param>
        /// <returns>实体列表</returns>
        public async Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> where)
        {
            return await _context.Set<TEntity>().Where(where).ToListAsync();
        }
        #endregion

        #region 按条件及指定字段升序返回指定数目一个实体列表
        /// <summary>
        /// 按条件及指定字段升序返回指定数目一个实体列表
        /// </summary>
        /// <typeparam name="type"></typeparam>
        /// <param name="where">lambda条件表达式</param>
        /// <param name="sort">排序字段</param>
        /// <param name="n">要获取的数量</param>
        /// <returns>实体列表</returns>
        public List<TEntity> Query<type>(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, type>> sort, int n)
        {
            return _context.Set<TEntity>().Where(where).OrderBy(sort).Take(n).ToList();//不使用ToList则返回IQueryTable<TEntity>
        }
        /// <summary>
        /// 按条件及指定字段升序返回指定数目一个实体列表 异步
        /// </summary>
        /// <typeparam name="type"></typeparam>
        /// <param name="where">lambda条件表达式</param>
        /// <param name="sort">排序字段</param>
        /// <param name="n">要获取的数量</param>
        /// <returns>实体列表</returns>
        public async Task<List<TEntity>> QueryAsync<type>(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, type>> sort, int n)
        {
            return await _context.Set<TEntity>().Where(where).OrderBy(sort).Take(n).ToListAsync();//不使用ToList则返回IQueryTable<TEntity>
        }
        /// <summary>
        /// 查询返回自定义model
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="where"></param>
        /// <param name="select"></param>
        /// <returns></returns>
        public IList<T> DesignQuery<T>(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, T>> select)
        {
            return _context.Set<TEntity>().Where(where).Select(select).ToList();
        }
        /// <summary>
        /// 查询返回自定义model 异步
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="where"></param>
        /// <param name="select"></param>
        /// <returns>例 Select(s=>new{ a=s.a })</returns>
        public async Task<IList<T>> DesignQueryAsync<T>(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, T>> select)
        {
            return await _context.Set<TEntity>().Where(where).Select(select).ToListAsync();
        }
        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="TKey">排序字段</typeparam>
        /// <param name="where">条件</param>
        /// <param name="pageIndex">当前页</param>
        /// <param name="keySelector">排序条件</param>
        /// <param name="isAsc">是否升序</param>
        /// <returns></returns>
        public async Task<IPagedList<TEntity>> PageQueryAsync<TKey>(Expression<Func<TEntity, bool>> where, int? pageIndex, Expression<Func<TEntity, TKey>> keySelector, bool isAsc)
        {
            int PageIndex = pageIndex ?? 1;
            int pageSize = NameConfig.pageSzie;
            int skip = (PageIndex - 1) * pageSize;
            var list = default(List<TEntity>);
            if (isAsc)
            {
                list = await _context.Set<TEntity>().OrderBy(keySelector).Where(where).
                    Skip(skip).Take(pageSize).Future().ToListAsync();
            }
            else
            {
                list = await _context.Set<TEntity>().OrderByDescending(keySelector).Where(where)
                    .Skip(skip).Take(pageSize).Future().ToListAsync();
            }
            var totalCount = _context.Set<TEntity>().Where(where).Future().Count();
            IPagedList<TEntity> pageList = new StaticPagedList<TEntity>(list, PageIndex, pageSize, totalCount);
            return pageList;
        }
        #endregion

        #endregion

        #region 统计
        /// <summary>
        /// 按条件统计
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public int Count(Expression<Func<TEntity, bool>> where)
        {
            return _context.Set<TEntity>().Count(where);
        }
        /// <summary>
        /// 按条件统计 异步
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<int> CountAsync(Expression<Func<TEntity, bool>> where)
        {
            return await _context.Set<TEntity>().CountAsync(where);
        }

        #endregion

        #region 更新

        #region 统一执行保存操作

        /// <summary>
        /// 调用数据库上下文统一执行保存操作
        /// </summary>
        /// <returns></returns>
        public int SaveChanges()
        {
            return _context.SaveChanges();
        }

        /// <summary>
        /// 调用数据库上下文统一执行保存操作 异步
        /// </summary>
        /// <returns></returns>
        public async Task<int> SaveChangesAsync()
        {
            return await _context.SaveChangesAsync();
        }
        #endregion

        #region 更新数据
        /// <summary>
        /// 更新所有属性
        /// </summary>
        /// <param name="entity"></param>
        public bool Update(TEntity entity)
        {
            var entry = this._context.Entry(entity);
            entry.State = EntityState.Modified;

            //如果数据没有发生变化
            if (!this._context.ChangeTracker.HasChanges())
            {
                return false;
            }
            return true;
        }
        // <summary>
        /// 实现按需要只更新部分更新
        /// <para>如：Update(u =>u.Id==1,u =>new User{Name="ok"});</para>
        /// </summary>
        /// <param name="where">The where.</param>
        /// <param name="entity">The entity.</param>
        public int Update(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TEntity>> entity)
        {
            return _context.Set<TEntity>().Where(where).Update(entity);
        }
        // <summary>
        /// 实现按需要只更新部分更新 异步
        /// <para>如：Update(u =>u.Id==1,u =>new User{Name="ok"});</para>
        /// </summary>
        /// <param name="where">The where.</param>
        /// <param name="entity">The entity.</param>
        public async Task<int> UpdateAsync(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TEntity>> entity)
        {
           return await _context.Set<TEntity>().Where(where).UpdateAsync(entity);
        }
        #endregion

        #endregion

        #region 写入
        /// <summary>
        /// 写入
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public void Insert(TEntity model)
        {
           _context.Set<TEntity>().Add(model);
        }
        /// <summary>
        /// 写入 异步
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task InsertAsync(TEntity model)
        {
           await _context.Set<TEntity>().AddAsync(model);
        }
        #endregion

    }
}
